/**************************************************************
 *
 * Copyright (c) 2008, ******, All Rights Reserved.
 *
 * 名 称:
 *		log.cpp
 * 位 置:
 *		src/pub/log.cpp
 * 描 述:
 *		公用日志类
 * 备 注:
 *		无
 * 修 改:
 *		2008-09-14  Simon   - 创建
 *
 **************************************************************/

extern "C"
{
#include <stdarg.h>
}
#include <string>
#include <iostream>
#include <fstream>
#include "pub/def.h"
#include "pub/err.h"
#include "pub/log.h"

using namespace std;

int Log::_logTo = 0;
int Log::_logLevel = 0;
string Log::_logFile = "";

static const int LOGLN_MAXLEN = 1024;

//----------------------------------------------
//	写调试日志
//----------------------------------------------
void Log::debug(const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];

	va_start(args, fmt);
	len = vsprintf(buf, fmt, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_DEBUG, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//	写调试日志
//----------------------------------------------
void Log::debugFL(const char* file, unsigned line, const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];
	char buf2[LOGLN_MAXLEN];

	va_start(args, fmt);
	sprintf(buf2, "<%s:%d> %s", file, line, fmt);
	len = vsprintf(buf, buf2, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_DEBUG, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//	写信息日志
//----------------------------------------------
void Log::info(const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];

	va_start(args, fmt);
	len = vsprintf(buf, fmt, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_INFO, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//	写信息日志
//----------------------------------------------
void Log::infoFL(const char* file, unsigned line, const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];
	char buf2[LOGLN_MAXLEN];

	va_start(args, fmt);
	sprintf(buf2, "<%s:%d> %s", file, line, fmt);
	len = vsprintf(buf, buf2, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_INFO, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//	写警告日志
//----------------------------------------------
void Log::warn(const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];

	va_start(args, fmt);
	len = vsprintf(buf, fmt, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_WARN, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//	写警告日志
//----------------------------------------------
void Log::warnFL(const char* file, unsigned line, const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];
	char buf2[LOGLN_MAXLEN];

	va_start(args, fmt);
	sprintf(buf2, "<%s:%d> %s", file, line, fmt);
	len = vsprintf(buf, buf2, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_WARN, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//	写错误日志
//----------------------------------------------
void Log::error(const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];

	va_start(args, fmt);
	len = vsprintf(buf, fmt, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_ERROR, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//	写错误日志
//----------------------------------------------
void Log::errorFL(const char* file, unsigned line, const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];
	char buf2[LOGLN_MAXLEN];

	va_start(args, fmt);
	sprintf(buf2, "<%s:%d> %s", file, line, fmt);
	len = vsprintf(buf, buf2, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	_log(LOGLVL_ERROR, getLogTo(), getLogFile(), buf, len);
}

//----------------------------------------------
//  写错误日志，并抛出异常
//----------------------------------------------
void Log::throwError(const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];

	va_start(args, fmt);
	len = vsprintf(buf, fmt, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	Log::error(buf);
	throw AppException(ERRCODE_APP, buf);
}

//----------------------------------------------
//  写错误日志，并抛出异常
//----------------------------------------------
void Log::throwError(unsigned errCode, const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];

	va_start(args, fmt);
	len = vsprintf(buf, fmt, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	Log::error(buf);
	throw AppException(errCode, buf);
}

//----------------------------------------------
//  写错误日志
//----------------------------------------------
void Log::throwErrorFL(const char* file, unsigned line, const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];
	char buf2[LOGLN_MAXLEN];

	va_start(args, fmt);
	sprintf(buf2, "<%s:%d> %s", file, line, fmt);
	len = vsprintf(buf, buf2, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	Log::error(buf);
	throw AppException(ERRCODE_APP, buf);
}


//----------------------------------------------
//  写错误日志
//----------------------------------------------
void Log::throwErrorFL(unsigned errCode, const char* file, unsigned line, const char* fmt, ...)
{
	va_list args;
	int len;
	char buf[LOGLN_MAXLEN];
	char buf2[LOGLN_MAXLEN];

	va_start(args, fmt);
	sprintf(buf2, "<%s:%d> %s", file, line, fmt);
	len = vsprintf(buf, buf2, args);
	va_end(args);

	if (len < 0 || len >= LOGLN_MAXLEN)
		throw AppException(ERRCODE_APP, "格式化输出错误");

	Log::error(buf);
	throw AppException(errCode, buf);
}

//----------------------------------------------
//	设置日志输出目标
//----------------------------------------------
void Log::setLogTo(int logTo)
{
	Log::_logTo = logTo;
}

//----------------------------------------------
//	获取日志输出目标
//----------------------------------------------
int Log::getLogTo()
{
	return _logTo;
}

//----------------------------------------------
//	设置日志级别
//----------------------------------------------
void Log::setLogLevel(int logLevel)
{
	Log::_logLevel = logLevel;
}

//----------------------------------------------
//	获取日志级别
//----------------------------------------------
int Log::getLogLevel()
{
	return _logLevel;
}

//----------------------------------------------
//	设置日志文件
//----------------------------------------------
void Log::setLogFile(const char* logFile)
{
	Log::_logFile = logFile;
}

//----------------------------------------------
//	获取日志文件
//----------------------------------------------
const char* Log::getLogFile()
{
	return _logFile.c_str();
}

//----------------------------------------------
//	写系统日志
//----------------------------------------------
void Log::_log(int lvl, int to, const char* file, const char* buff, unsigned len)
{
	if (_logLevel > lvl)
		return;

	ofstream fout;
	const char* p = buff;
	//for (unsigned i= 0; i < len;)
	{
		//if (*p != 0x00)
		{
			switch (to)
			{
			/*case LOGTO_TUXEDO:
			 userlog("%s\n", p);
			 break;*/

			case LOGTO_STDOUT:
				cout << p << endl;
				break;

			case LOGTO_STDERR:
				cerr << p << endl;
				break;

			case LOGTO_FILE:
				try
				{
					fout.open(file, ios::app);
					fout << p << endl;
				}
				catch (...)
				{
					fout.close();
					throw AppException(ERRCODE_APP, "写日志文件错误");
				}
				break;

			default:
				throw AppException(ERRCODE_APP, "不支持的日志输出选项");
			}

			//p += strlen(p);
		}
		//else
		{
			//p++;
		}
	}
}
